package com.cneport.das.server.api;

import com.cneport.das.common.model.base.Result;
import com.cneport.das.common.model.trans.*;
import com.cneport.das.common.utils.*;
import com.cneport.das.server.conf.ConfigCaches;
import com.cneport.das.server.trans.conf.Authen;
import com.cneport.das.server.trans.core.*;
import com.cneport.das.server.trans.parse.ParserAndWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author GavinZhang
 * @version 1.0
 * @desc： Server 接受 Client请求
 * @company 东方物通科技有限（北京）公司
 * @date 2021/8/26 8:18
 */
@RestController
@Slf4j
public class TransController {
    @Autowired
    private ParserAndWrapper parserAndWrapper;

    @Autowired
    private TransService serverService;

    @Autowired
    private ReceiveProtect receiveProtect;

    @Autowired
    private BizRecorder bizRecorder;


    @Autowired
    private ConfigCaches configCaches;

    @Autowired
    private AuthCheckService authCheckService;

    @Autowired
    SecurityKeyService securityKeyService;

    @PostMapping(value = "/putServerMsg")
    public String sendMsg(HttpServletRequest request, @RequestBody String encodedStr) {

        try {
            encodedStr = URLDecoder.decode(encodedStr, "UTF-8");
            if (encodedStr.endsWith("=")) {
                encodedStr = encodedStr.substring(0, encodedStr.length() - 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        ClientPutRequest clientPutRequest = JAXBUtils.xml2Obj(ClientPutRequest.class, encodedStr);

        ClientPutRequest.ReqHead reqHead = clientPutRequest.getReqHead();

        String guid = reqHead.getGuid();
        String senderId = reqHead.getSenderId();
        String corpNo = reqHead.getCopNo();
        String MsgType = reqHead.getMsgType();
        ClientPutRequest.ReqData reqData = clientPutRequest.getReqData();
        String encoderVer = StringUtil.isBlank(reqData.getEncoderVer()) ? "1.0" : reqData.getEncoderVer();

        String pubKey = getPubKeyPath(corpNo, encoderVer);
        if (StringUtil.isBlank(pubKey)) {
            return JAXBUtils.obj2Xml(fail(guid, "-1", "秘钥文件不存在！", clientPutRequest.getAddInfos()));
        }
        //签名，默认内部软签
        if (!SignUtil.check(clientPutRequest)) {
            return JAXBUtils.obj2Xml(fail(guid, "-1", "签名不正确！", clientPutRequest.getAddInfos()));
        }
        //解密
        clientPutRequest = EncryptUtil.decode(clientPutRequest, pubKey, false);


        //暂不做任何处理，为后续控制预留
        String copLic = clientPutRequest.getReqHead().getCopLic();

        boolean isPermit = authCheckService.verify(corpNo, copLic);
        if (!isPermit) {
            return JAXBUtils.obj2Xml(fail(guid, "-1", "未被授权的调用！", clientPutRequest.getAddInfos()));
        }

        String msg = parserAndWrapper.wrapperPut(clientPutRequest);

        String reqStr = JAXBUtils.obj2Xml(clientPutRequest);
        //记日志
        bizRecorder.write(senderId, MsgType, guid, "上传报文：" + reqStr);
        log.info("上传报文：\n" + reqStr);

        String queueName = serverService.getQueueName(corpNo, QueueTypeEnum.REQ_QUEUE.getValue());
        //获取队列名称
        if (StringUtil.isBlank(queueName)) {
            return JAXBUtils.obj2Xml(fail(guid, "-1", "发送队列不存在！", clientPutRequest.getAddInfos()));
        } else {
            //发送消息
            Result reslt = serverService.sendMsg(queueName, msg);

            if ("-1".equals(reslt.getCode())) {
                return JAXBUtils.obj2Xml(fail(guid, "-1", "消息发送失败！", clientPutRequest.getAddInfos()));
            } else {
                return JAXBUtils.obj2Xml(success(guid, clientPutRequest.getAddInfos()));
            }
        }
    }

    @PostMapping("/getServerMsg")
    public String receiveMsg(HttpServletRequest request, @RequestBody String
            encodedStr) {
        try {
            encodedStr = URLDecoder.decode(encodedStr, "UTF-8");
            if (encodedStr.endsWith("=")) {
                encodedStr = encodedStr.substring(0, encodedStr.length() - 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        ClientGetRequest clientGetRequest = JAXBUtils.xml2Obj(ClientGetRequest.class, encodedStr);


        ClientGetRequest.ReqHead reqHead = clientGetRequest.getReqHead();

        String guid = reqHead.getGuid();
        String corpNo = reqHead.getCopNo();
        String senderId = reqHead.getSenderId();
        String encoderVer = reqHead.getEncoderVer();
        String pubKey = getPubKeyPath(corpNo, encoderVer);

        //验签
        if (!SignUtil.check(clientGetRequest)) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "签名不正确！", clientGetRequest.getAddInfos()));
        }

        if (StringUtil.isBlank(pubKey)) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "秘钥文件不存在！", clientGetRequest.getAddInfos()));
        }
        //解密
        clientGetRequest = EncryptUtil.decode(clientGetRequest, pubKey, false);
        String copLic = clientGetRequest.getReqHead().getCopLic();

        boolean isPermit = authCheckService.verify(corpNo, copLic);
        if (!isPermit) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "未被授权的调用！", clientGetRequest.getAddInfos()));
        }

        String reqStr = JAXBUtils.obj2Xml(clientGetRequest);
        //记日志
        bizRecorder.write(senderId, "fetch", guid, "上传报文：" + reqStr);
        log.info("请求查询：" + reqStr);

        int maxCnt = reqHead.getMaxCnt();

        boolean pass = receiveProtect.pass(corpNo);
        if (!pass) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "请求太过频繁，稍后再试！", clientGetRequest.getAddInfos()));
        } else {
            //获取队列名称
            String queueName = serverService.getQueueName(corpNo, QueueTypeEnum.RCV_QUEUE.getValue());
            if (StringUtil.isBlank(queueName)) {
                return JAXBUtils.obj2Xml(getFail(guid, "-1", "接收队列不存在！", clientGetRequest.getAddInfos()));
            } else {

                //收取消息
                Result reslt = serverService.receiveMsg(queueName, maxCnt);
                if ("-1".equals(reslt.getCode())) {
                    return JAXBUtils.obj2Xml(getFail(guid, "-1", "消息接收失败！", clientGetRequest.getAddInfos()));
                } else {
                    List<String> messages = reslt.getContent();
                    if (messages.size() == 0) {
                        return JAXBUtils.obj2Xml(getFail(guid, "0", "暂时没有您需要的消息！", clientGetRequest.getAddInfos()));

                    } else {
                        List<String> respDatas = new ArrayList<>();
                        for (String data : messages) {
                            respDatas.add(data);
                            log.info("查到报文：" + data);
                        }
                        respDatas = EncryptUtil.encode(respDatas, pubKey, false);
                        return JAXBUtils.obj2Xml(getSucc(guid, respDatas, clientGetRequest.getAddInfos()));
                    }
                }
            }
        }

    }


    @GetMapping("/getMsgByClientProxy")
    public String receiveByClientProxy(@NotNull @RequestParam String guid, @NotNull @RequestParam String copNo, @NotNull @RequestParam String copLic, @NotNull @RequestParam String maxCnt, @NotNull @RequestParam String encoderVer) {
        log.info("CRP: " + DateUtil.now() + "-->【guid】: " + guid + " 【copNo】: " + copNo + " 【copLic】: " + copLic + " 【maxCnt】: " + maxCnt + " 【encoderVer】: " + encoderVer);
        Integer cnt = Integer.parseInt(maxCnt == null ? "10" : maxCnt);

        Authen corpAuth = configCaches.getCorpAuthByCorpNo(copNo);

        String pubKey = getPubKeyPath(copNo, encoderVer);
        if (StringUtil.isBlank(pubKey)) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "秘钥文件不存在！", null));
        }

        copLic = EncryptUtil.decode(copLic, pubKey, false);

        boolean isPermit = authCheckService.verify(copNo, copLic);
        if (!isPermit) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "未被授权的调用！", null));
        }

        if (corpAuth == null) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "没有找到相关公司的配置信息", null));
        }
        String rcvQueue = corpAuth.getRcvQueue();
        if (StringUtil.isBlank(rcvQueue)) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "没有配置相关接收队列信息", null));
        }
        //收取消息
        Result reslt = serverService.receiveMsg(rcvQueue, cnt);
        if ("-1".equals(reslt.getCode())) {
            return JAXBUtils.obj2Xml(getFail(guid, "-1", "消息接收失败！", null));
        } else {

            List<String> messages = reslt.getContent();
            if (messages.size() == 0) {
                return JAXBUtils.obj2Xml(getFail(guid, "0", "暂时没有您需要的消息！", null));

            } else {
                List<String> respDatas = new ArrayList<>();
                for (String data : messages) {
                    respDatas.add(data);
                    log.info("查到报文：" + data);

                }
                respDatas = EncryptUtil.encode(respDatas, pubKey, false);
                return JAXBUtils.obj2Xml(getSucc(guid, respDatas, null));
            }
        }
    }

    private String getPubKeyPath(String corpNo, String encoderVer) {
        if (StringUtil.isBlank(corpNo) || StringUtil.isBlank(encoderVer)) {
            log.error("获取秘钥的参数不正确！");
            return "";
        }


        String file = securityKeyService.getKeyFilePath(corpNo, encoderVer, null);
        File fl = new File(file);
        if (!fl.exists()) {
            log.error("秘钥文件不存在！");
            return "";
        }
        return file;
    }

    private ClientPutResponse fail(String guid, String code, String msg, AddInfos addInfos) {
        ClientPutResponse response = new ClientPutResponse();
        response.setAddInfos(addInfos);
        response.setRespHead(ClientPutResponse.RespHead.builder().reqGuid(guid).respCode(code).respMsg(msg).respTime(DateUtil.C14()).build());
        return response;

    }

    private ClientPutResponse success(String guid, AddInfos addInfos) {
        ClientPutResponse response = new ClientPutResponse();
        response.setAddInfos(addInfos);
        response.setRespHead(ClientPutResponse.RespHead.builder().reqGuid(guid).respCode("0").respMsg("").respTime(DateUtil.C14()).build());
        return response;

    }

    private ClientGetResponse getFail(String guid, String code, String msg, AddInfos addInfos) {
        ClientGetResponse response = new ClientGetResponse();
        response.setAddInfos(addInfos);
        response.setRespHead(ClientGetResponse.RespHead.builder().reqGuid(guid).respCode(code).respMsg(msg).respTime(DateUtil.C14()).build());
        return response;

    }

    private ClientGetResponse getSucc(String guid, List<String> datas, AddInfos addInfos) {
        ClientGetResponse response = new ClientGetResponse();
        response.setAddInfos(addInfos);
        response.setRespHead(ClientGetResponse.RespHead.builder().reqGuid(guid).respCode("0").respMsg("").respTime(DateUtil.C14()).build());
        response.setRespData(new RespData(datas));
        return response;

    }

    @GetMapping("/regist")
    public String regist(@NotNull @RequestParam String ip, @NotNull @RequestParam String mac, @NotNull @RequestParam String corpNoStr) {
        log.info("regist--> 【IP】:" + ip + ",【mac】:" + mac + ",【corps】:" + corpNoStr);
        String[] copNos = corpNoStr.split("#");
        if (copNos != null && copNos.length > 0) {
            authCheckService.regist(ip, mac, Arrays.asList(copNos));
            return "0";
        }
        return "-1";
    }
}